import { defineStore } from "pinia"
import router from "@/router"
import useEventEmitter from "@hooks/useEventEmitter"
import tabBarOption from "@/tabBar"
import commonUtil from "@utility/commonUtil.ts"

export const routerEventEmitter: UseEventEmitter.EventEmitter =
	useEventEmitter()
const tabBar: Array<string> = tabBarOption.map(
	(el: TabBar.OptionsItem) => el.pathName
) //tabbar页面

/**
 * @method defaultCurrentPagesFun 默认当前路由
 * */
const defaultCurrentPagesFun = (): RouterStore.Pages => {
	let defaultCurrentPages: RouterStore.Pages = []
	if (tabBar.length) {
		defaultCurrentPages = [
			{
				pathName: tabBar[0],
				params: [],
				cache: true,
			},
		]
	}
	return defaultCurrentPages
}

/**
 * @method isNavigate 判断导航
 * @param navigateInfo { RouterStore.NavigateInfo } 导航信息
 * */
const isNavigate = (navigateInfo: RouterStore.NavigateInfo): Array<boolean> => {
	let isTabBar: boolean = false
	let isNavStr: boolean = false
	if (commonUtil.isStr(navigateInfo)) {
		isNavStr = true
		if (tabBar.includes(navigateInfo as string)) {
			isTabBar = true
		}
	} else {
		isNavStr = false
		if (tabBar.includes((navigateInfo as RouterStore.GoPagePar).pathName)) {
			isTabBar = true
		}
	}
	return [isTabBar, isNavStr]
}

const useRouterStore: RouterStore.Store = defineStore("routerStore", {
	state: (): RouterStore.State => ({
		currentPages: defaultCurrentPagesFun(), //当前已跳转页面列表
		historyPages: [], //当前已回退页面列表
	}),
	actions: {
		//actions是store的方法methods
		/***
		 * @method navigateTo 保留当前页面，跳转某个页面，不能跳转跳转到tabBar页面
		 * @param navigateInfo { RouterStore.NavigateInfo } 导航信息
		 navigateInfo = pathName
		 navigateInfo = {
		 pathName:'', 路由名称
		 success: ()=>{} 路由跳转成功函数
		 }
		 * */
		async navigateTo(
			navigateInfo: RouterStore.NavigateInfo
		): Promise<void> {
			const [isTabBar, isNavStr]: Array<boolean> =
				isNavigate(navigateInfo)
			if (!isTabBar) {
				let pathName: string = ""
				if (isNavStr) {
					pathName = navigateInfo as string
					await router.push(pathName)
					this.update(pathName)
				} else {
					const info: RouterStore.GoPagePar =
						navigateInfo as RouterStore.GoPagePar
					await router.push(info.pathName)
					this.update(info.pathName)
					if (commonUtil.isFun(info.success)) info.success?.()
				}
			}
		},
		/**
		 * @method navigateBack 关闭当前页面，返回上一页面或多级页面
		 * @param backInfo { RouterStore.BackInfo } 导航信息 返回的页面数，默认1
		 backInfo={
		 delta: 1,
		 success: ()=>{} 路由跳转成功函数
		 }
		 * */
		navigateBack(backInfo: RouterStore.BackInfo): void {
			let delta: number = 1
			let info: Partial<RouterStore.BackPagePar> = {}
			const backPageRouter: RouterStore.PageItem =
				this.currentPages[this.currentPages.length - 2]
			this.updateCacheStatus(backPageRouter.pathName)
			//返回一个页面由路由监听处理，主要为了兼容浏览器自带的返回
			if (commonUtil.isJson(backInfo)) {
				info = backInfo as RouterStore.BackPagePar
				delta = info.delta || 1
			}
			if (delta > 1) {
				router.go(-delta)
				this.delete(delta)
			} else {
				router.back()
			}
			// 返回页面，真实内容的渲染会慢一拍；这里用定时处理
			if (info && commonUtil.isFun(info.success)) {
				const navigateBackTimeout = setTimeout(() => {
					info.success?.()
					clearTimeout(navigateBackTimeout)
				}, 30)
			}
		},
		/***
		 * @method switchTarBar 跳转到tabBar页面，并关闭其他所有非tabBar页面
		 * @param navigateInfo { RouterStore.NavigateInfo } 导航信息
		 navigateInfo = pathName
		 navigateInfo = {
		 pathName:'', 路由名称
		 success: ()=>{} 路由跳转成功函数
		 }
		 * */
		async switchTarBar(
			navigateInfo: RouterStore.NavigateInfo
		): Promise<void> {
			const [isTabBar, isNavStr]: Array<boolean> =
				isNavigate(navigateInfo)
			if (isTabBar) {
				let pathName: string
				if (isNavStr) {
					pathName = navigateInfo as string
					await router.replace(pathName)
				} else {
					const info: RouterStore.GoPagePar =
						navigateInfo as RouterStore.GoPagePar
					pathName = info.pathName
					await router.replace(pathName)
					if (commonUtil.isFun(info.success)) info.success?.()
				}
				this.currentPages = [
					{
						pathName: pathName,
						params: [], //emit传递的参数集合
						cache: true, //页面是否缓存
					},
				]
				//跳转tabbar页，相当于重新开始路由跳转，需清空已回退页面列表
				this.historyPages = []
			}
		},
		/***
		 * @method redirectTo 关闭当前页面，跳转某个页面。但是不允许跳转到tabbar页面
		 * @param navigateInfo { RouterStore.NavigateInfo } 导航信息
		 navigateInfo = pathName
		 navigateInfo = {
		 pathName:'', 路由名称
		 success: ()=>{} 路由跳转成功函数
		 }
		 * */
		async redirectTo(
			navigateInfo: RouterStore.NavigateInfo
		): Promise<void> {
			const [isTabBar, isNavStr]: Array<boolean> =
				isNavigate(navigateInfo)
			if (!isTabBar) {
				let pathName: string = ""
				if (isNavStr) {
					pathName = navigateInfo as string
					await router.replace(pathName)
				} else {
					const info: RouterStore.GoPagePar =
						navigateInfo as RouterStore.GoPagePar
					pathName = info.pathName
					await router.replace(pathName)
					if (commonUtil.isFun(info.success)) info.success?.()
				}
				this.deleteHistory(pathName)
			}
		},
		/**
		 * @method emit 触发特定事件，并依次调用与该事件关联的所有监听器函数
		 * @param eventName {String} 事件名
		 * @param par 传给监听事件的参数
		 * */
		emit(eventName: string, par: Record<string, unknown>): void {
			const currentPage: RouterStore.PageItem =
				this.currentPages[this.currentPages.length - 1]
			const paramIndex = currentPage.params?.findIndex(
				(el: object): boolean => Reflect.ownKeys(el)[0] == eventName
			)
			if (paramIndex > -1) {
				currentPage.params[paramIndex][eventName] = par
			} else {
				currentPage.params.push({
					[eventName]: par,
				})
			}
			routerEventEmitter.emit(`${location.pathname}.${eventName}`, par)
		},
		/**
		 * @method on 事件监听器
		 * @param eventName {String} 事件名称
		 * @param callback {Function} 监听函数
		 * */
		on(eventName: string, callback: () => void): void {
			if (eventName) {
				routerEventEmitter.addOnceListener(
					`${location.pathname}.${eventName}`,
					callback
				)
			}
		},
		/**
		 * @method eventOn events事件绑定，主要用于页面返回传参
		 * @param eventName {String} 事件名称
		 * @param callback {Function} 监听函数
		 * */
		eventOn(eventName: string, callback: () => void): void {
			this.on(`events.${eventName}`, callback)
		},
		/**
		 * @method eventEmit events事件发射器，主要用于页面返回传参
		 * @param eventName {String} 事件名
		 * @param par 传给监听事件的参数
		 * */
		eventEmit(eventName: string, par: Record<string, unknown>) {
			routerEventEmitter.emit(
				`${location.pathname}.events.${eventName}`,
				par
			)
		},
		/**
		 * @method update 更新路由
		 * @param pathName {String} 路由name
		 * */
		update(pathName: string): void {
			const pageIndex: number = this.currentPages.findIndex(
				(element: RouterStore.GoPagePar): boolean =>
					element.pathName == pathName
			)
			let routerInfo: RouterStore.PageItem = {
				pathName: pathName,
				params: [], //emit传递的参数集合
				cache: true, //页面是否缓存
			}
			if (pageIndex > -1) {
				//如果已存在路由直接替换原有信息
				this.currentPages[pageIndex] = routerInfo
			} else {
				//如果不存在路由添加路由信息
				this.currentPages.push(routerInfo)
			}
			this.deleteHistory(pathName)
		},
		/**
		 * @method delete 移除页面路由
		 * @param delta {Number} 返回的页面数
		 * */
		delete(delta: number): void {
			const historyPages: RouterStore.Pages = this.currentPages.splice(
				this.currentPages.length - delta,
				delta
			)
			this.currentPages[this.currentPages.length - 1].cache = true
			if (this.currentPages.length > 1) {
				this.historyPages.unshift(...historyPages)
			} else {
				//当前列表只有一个时，说明此时是在tabbar页，相当于重新开始路由跳转，需清空已回退页面列表
				this.historyPages = [...historyPages]
			}
		},
		/**
		 * @method deleteHistory 移除页面历史路由
		 * @param pathName {String} 路由名字
		 * @param addCurrentPages {Boolean} 是否添加到当前路由
		 * */
		deleteHistory(
			pathName: string,
			addCurrentPages: boolean = false
		): void {
			if (this.historyPages.length) {
				const spliceCount: number = this.historyPages.findIndex(
					(element: RouterStore.PageItem): boolean =>
						element.pathName == pathName
				)
				const historyPages: RouterStore.Pages =
					this.historyPages.splice(0, spliceCount + 1)
				if (addCurrentPages) {
					historyPages.forEach(element => {
						element.cache = true
					})
					this.currentPages.push(...historyPages)
				}
			}
		},
		/**
		 * @method updateCacheStatus 更新某个页面缓存状态
		 * @param pathName 路由名
		 * */
		updateCacheStatus(pathName: string): void {
			this.currentPages.forEach(element => {
				if (element.pathName == pathName) {
					element.cache = true
				}
			})
		},
		/**
		 * @method resetCacheStatus 重置页面缓存状态
		 * @description 用于页面刷新时
		 * */
		resetCacheStatus() {
			const pathName = location.pathname.substring(1)
			if (this.currentPages.length) {
				this.currentPages.forEach(element => {
					element.cache = pathName == element.pathName ? true : false
				})
			}
			if (this.historyPages.length) {
				this.historyPages.forEach(element => {
					element.cache = pathName == element.pathName ? true : false
				})
			}
		},
	},
	persist: {
		storage: sessionStorage,
	},
})

export default useRouterStore
